///////////////////////////////////////////////////////////
// 
//  MyOozeBall.cpp
// 
//  Authors:  Jeremy Bennett
//
///////////////////////////////////////////////////////////

// Local Includes
#include "stdafx.h"
#include "MyOozeBall.h"
#include "MyContext.h"

// SDL Includes
#include <SDL_opengl.h>

// Bullet Includes
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
#include <BulletCollision/CollisionShapes/btSphereShape.h>

#include <LinearMath/btDefaultMotionState.h>

// System Includes
int g_ID = 0;

MyOozeBall::MyOozeBall( const btScalar   fRadius,
                        const btVector3 &vOrigin, 
                        const btScalar   fMass )
: MySphere(fRadius,vOrigin,fMass),
  _iID(g_ID++),
  _iHappiness(0),
  _bSearchHit(false),
  _iSearchAng(0),
  _vSearchVec(0.0f,0.0f,0.0f),
  _vSearchMov(0.0f,0.0f,0.0f)
{
    _eType = my_ooze;

    for ( int i=0 ; i<max_factors ; i++ ) {
        _iFactors[i] = (rand() % 101);
    }

    _updateSearchAngle();
}

MyOozeBall::~MyOozeBall() 
{
}

bool 
MyOozeBall::render( MyContext *ctx )
{
    _vCol[3] = 1.0f;
    _vCol[2] = 0.0f;
    if ( _iHappiness >= 0 ) {
        _vCol[1] = _iHappiness/1000.0f;
        _vCol[0] = 0.0f;
    } else {
        _vCol[1] = 0.0f;
        _vCol[0] = _iHappiness/-1000.0f;
    }
    
    _updateSearchAngle();

    // Render the sphere
    MySphere::render(ctx);

    return true;
}

bool 
MyOozeBall::findNeighbors( btCollisionWorld *pWorld )
{
    btVector3 aVec[8] = { btVector3(-5, 0, 0),
                          btVector3( 5, 0, 0),
                          btVector3( 0,-5, 0),
                          btVector3( 0, 5, 0),
                          btVector3( 3.54f, 3.54f, 0),
                          btVector3(-3.54f, 3.54f, 0),
                          btVector3( 3.54f,-3.54f, 0),
                          btVector3(-3.54f,-3.54f, 0) };
    int                   nHit = 0;
    btScalar	          m[16];
    MyShape              *pShp = NULL;
    btRigidBody          *pRigBdy = NULL;
    btDefaultMotionState *pMotState = (btDefaultMotionState*)getMotionState();
    pMotState->m_graphicsWorldTrans.getOpenGLMatrix(m);

    btVector3 rS(m[12],m[13],m[14]), rE;

#if 0
    glEnable(GL_POINT_SMOOTH);
    glEnable(GL_LINE_SMOOTH);

    glDisable(GL_LIGHTING);

    glColor4f(0.0f,0.0f,1.0f,1.0f);
    glPointSize( 5.0f );
#endif

    if ( !_bIsPicked ) {
        rE = rS + _vSearchVec;
        btCollisionWorld::ClosestRayResultCallback pickCB(rS,rE);
        pWorld->rayTest(rS,rE,pickCB);

        _bSearchHit = pickCB.hasHit();
        
        if (_bSearchHit) {
            pRigBdy = btRigidBody::upcast(pickCB.m_collisionObject);
            pShp = dynamic_cast<MyShape*>(pRigBdy);
        }
        if ( pShp && pShp->type() == my_ooze && !((MyOozeBall*)pShp)->isPicked() ) {

            btVector3 vDis = pickCB.m_hitPointWorld - rS;
            float fDis = pickCB.m_hitPointWorld.distance2(rS);

            if ( fDis > 25 ) {
                _vSearchMov = _vSearchVec/1800;
                //setLinearVelocity( btVector3( 0, 0, 0 ) );
                applyCentralImpulse( _vSearchMov );
                // Ensure the activation state and deactivation
                // time are set correctly
                setActivationState(ACTIVE_TAG);
                setDeactivationTime(0.0f);
            } else {
                // When near another Ooze ball stop linear
                // velocity on the x and y axis.
                // NOTE: The z axis is left active so that
                // the balls will fall to the floor.
                _vSearchMov = getLinearVelocity();
                _vSearchMov[0] = 0;
                _vSearchMov[1] = 0;
                setLinearVelocity( _vSearchMov );
            }

#if 0
            glColor4f(1.0f,1.0f,0.0f,1.0f);
#endif
        } else {
            _bSearchHit = false;
            _updateSearchAngle();
        }

#if 0
        glBegin(GL_POINTS);
        glVertex3f(rE[0],rE[1],rE[2]);
        glEnd();
#endif
    }

#if 0
        glBegin(GL_POINTS);
        glVertex3f(rS[0],rS[1],rS[2]);
        glEnd();
#endif

    _iHappiness = 0;

    pShp = NULL;
    for ( int i=0 ; i<8 ; i++ ) {
        pShp = NULL;

        rE = rS - aVec[i];
       
        btCollisionWorld::ClosestRayResultCallback pickCB(rS,rE);
        pWorld->rayTest(rS,rE,pickCB);
        if (pickCB.hasHit()) {
            pRigBdy = btRigidBody::upcast(pickCB.m_collisionObject);
            pShp = dynamic_cast<MyShape*>(pRigBdy);
        }
        if (pShp && pShp->type() == my_ooze ) {
            MyOozeBall *pBall = (MyOozeBall*)pRigBdy;

            nHit++;

            _iHappiness += compatibility(pBall);

#if 0
            glColor4f(1.0f,1.0f,0.0f,1.0f);
#endif
        } else {
#if 0
            glColor4f(1.0f,0.0f,0.0f,1.0f);
#endif
        }

#if 0
        glBegin(GL_POINTS);
        glVertex3f(rE[0],rE[1],rE[2]);
        glEnd();
#endif
    }
    if (nHit==0) {
        _iHappiness = 0;
    }

#if 0
    glEnable(GL_LIGHTING);
#endif

    /*
    glBegin(GL_LINE);
    glVertex3f(-10.0f,0.0f,-25.0f);
    glVertex3f(10.0f,0.0f,-25.0f);
    glEnd();
    */

    return true;
}

void 
MyOozeBall::_updateSearchAngle()
{
    if ( !_bSearchHit ) {
        btScalar m[16];
        btDefaultMotionState *pMotState = (btDefaultMotionState*)getMotionState();
        pMotState->m_graphicsWorldTrans.getOpenGLMatrix(m);

        _iSearchAng += 1;
        _iSearchAng %= 360;
        float fRad  = _iSearchAng/57.2957795f;
        _vSearchVec[0] = 180*sin(fRad);
        _vSearchVec[1] = 180*cos(fRad);
        _vSearchVec[2] = 0.0f; // m[14];
    }
}

int 
MyOozeBall::compatibility( const MyOozeBall *pBall )
{
    int iHap  = 0,
        iOpp  = 0,
        iSoul = 0;

    for ( int i=0 ; i<max_factors ; i++ ) {
        int dif = abs( _iFactors[i] - pBall->_iFactors[i] );
        
        bool bOpp = ( (_iFactors[i] < 50 && pBall->_iFactors[i] > 50) ||
                      (_iFactors[i] > 50 && pBall->_iFactors[i] < 50) );

        if ( bOpp )    { iOpp++;  }
        if ( dif < 5 ) { iSoul++; }

        if ( dif <= 25 ) {
            iHap += (25-dif);
        } else {
            iHap -= (dif-2);
        }
    }

    if ( iOpp == max_factors || iSoul == max_factors ) {
        iHap = 125;
    }

    return iHap;
}
